package de.kraenksoft.android.cinemaExample.presenters;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.kraenksoft.android.cinemaExample.R;
import de.kraenksoft.android.cinemaExample.UFProgramApplication;
import de.kraenksoft.android.cinemaExample.model.Movie;
import de.kraenksoft.android.cinemaExample.model.Screening;
import de.kraenksoft.android.cinemaExample.model.Theater;
import de.kraenksoft.android.cinemaExample.utils.DateUtil;
import de.kraenksoft.android.cinemaExample.views.MovieListView;

public class MovieListPresenterImpl implements MovieListPresenter {

	private MovieListView view = null;
	private Theater theater;
	/**
	 * The currently selected day that will be displayed. The hour and minute
	 * are always 13:00.
	 * The field is protected so that test classes can set it independently.
	 */
	protected Calendar curSelDay;
	private boolean isModelSet;
	private Exception exception;

	public MovieListPresenterImpl() {
		curSelDay = getCurrentDay();
		curSelDay.set(Calendar.HOUR_OF_DAY, 13);
		curSelDay.set(Calendar.MINUTE, 0);
		curSelDay.set(Calendar.SECOND, 0);
		curSelDay.set(Calendar.MILLISECOND, 0);
	}

	protected Calendar getCurrentDay() {
		return GregorianCalendar.getInstance();
	}

	@Override
	public void setView(MovieListView view) {
		this.view = view;
		updateView();
	}

	private void updateView() {
		if (view != null) {
			if(isModelSet){
				view.showLoadingData(false);
			}else{
				view.showLoadingData(true);
			}
			if (theater == null) {
				String noData = UFProgramApplication.getInstance().getApplicationContext().getResources().getString(R.string.no_data); 
				view.setCaption(noData);
				view.setLastDayButtonVisible(false);
				view.setNextDayButtonVisible(false);
				List<Map<String, String>> emptyMovieList = new ArrayList<Map<String, String>>();
				view.setMovies(emptyMovieList);
				updateErrorText();
			} else {
				updateCaption();
				updateButtons();
				updateMovies();
				updateErrorText();
			}
		}
	}

	private void updateErrorText() {
		if(this.exception != null){
			String connectionFailed = UFProgramApplication.getInstance().getApplicationContext().getResources().getString(R.string.connection_failed); 
			view.setErrorText(connectionFailed);
		}else{
			view.setErrorText("");
		}
		
	}

	private void updateCaption() {
		assert view != null;
		DateFormat sdf = SimpleDateFormat.getDateInstance(DateFormat.SHORT);
		String dateCaptionString = DateUtil.getDayTitleForDate(curSelDay
				.getTime()) + " " + sdf.format(curSelDay.getTime());
		view.setCaption(dateCaptionString);
		
	}

	private void updateButtons() {
		assert view != null;
		assert theater != null;
		Date lastScreeningDate = theater.getLastScreening().getStartTime();
		if ((DateUtil.datesOnSameDay(curSelDay.getTime(), lastScreeningDate) || curSelDay
				.getTime().compareTo(lastScreeningDate) > 0)) {
			view.setNextDayButtonVisible(false);
		} else {
			view.setNextDayButtonVisible(true);
		}
		view.setLastDayButtonVisible(false);
		Date currentDate = getCurrentDay().getTime();
		if ((DateUtil.datesOnSameDay(curSelDay.getTime(), currentDate) || curSelDay
				.getTime().compareTo(currentDate) < 0)) {
			view.setLastDayButtonVisible(false);

		} else {
			view.setLastDayButtonVisible(true);
		}
	}
	
	private void updateMovies() {
		assert view != null;
		List<Map<String, String>> movies = getMoviesOfDate(curSelDay.getTime());
		view.setMovies(movies);
	}
	
	private List<Map<String, String>> getMoviesOfDate(Date date) {
		assert theater != null;
		List<Map<String, String>> movieMaps = new ArrayList<Map<String, String>>();
		for (Movie movie : theater.getMovies()) {
			Map<String, String> movieMap = new HashMap<String, String>();
			movieMap.put(MovieListView.MOVIENAMEKEY, movie.getName());
			String times = null;
			SimpleDateFormat df = new SimpleDateFormat("HH:mm");
			for (Screening screening : movie.getScreeningsByDate(date)) {
				if (times == null) {
					times = df.format(screening.getStartTime());
				} else {
					times += "\n" + df.format(screening.getStartTime());
				}
			}
			if (times != null) {
				movieMap.put(MovieListView.MOVIESCREENINGSKEY, times);
				movieMaps.add(movieMap);
			}
		}
		return movieMaps;
	}

	@Override
	public void nextDayClicked() {
		curSelDay.add(Calendar.DAY_OF_YEAR, 1);
		updateView();
	}

	@Override
	public void lastDayClicked() {
		curSelDay.add(Calendar.DAY_OF_YEAR, -1);
		updateView();
	}

	@Override
	public void setModel(Theater theater) {
		if(theater != null){
			this.isModelSet = true;
			this.theater = theater;
		}else{
			this.isModelSet = false;
			this.theater = null;
		}
		this.exception = null;
		updateView();
	}

	@Override
	public void setException(Exception loadTheaterException) {
		this.isModelSet = true;
		this.theater = null;
		this.exception = loadTheaterException;
		updateView();
	}

}
